#pragma once

#include <vector>
#include <stdio.h>
#include <string>
#include <algorithm>

/*
*   prependable  |  readable byte  |  writable bytes  |
*   0    <=      |                 |        <=        |
*           readerIndex       writerIndex            size
*/
class Buffer
{
public:
    static const size_t kCheapPrepend = 8; // 数据报的长度
    static const size_t kInitalSize = 1024; // 缓冲区初始大小

    explicit Buffer(size_t initalSize = kInitalSize)
        :buffer_(kCheapPrepend + initalSize)
        ,readerIndex_(kCheapPrepend) // 跳过数据报的长度，从缓冲区开始读数据
        ,writerIndex_(kCheapPrepend)
    {}

    size_t readableBytes() const
    {
        return writerIndex_ - readerIndex_;
    }

    size_t writableBytes() const
    {
        return buffer_.size() - writerIndex_;
    }

    size_t prependableBytes() const
    {
        return readerIndex_;
    }

    // 返回缓冲区中可读数据的起始地址
    const char* peek() const
    {
        return begin() + readerIndex_;
    }

    // onMessage string <- Buffer
    void retrieve(size_t len) // retrieve:取回
    {
        if(len < readableBytes())
        {
            // 应用只读取了可读缓冲区数据的一部分，就是len，还剩下readerIndex_ += len -> writerIndex_（这个区间的数据没读） 
            readerIndex_ += len; 
        }
        else // len == readableBytes()
        {   
            retrieveAll();
        }
    }

    void retrieveAll()
    {
        readerIndex_ = writerIndex_ = kCheapPrepend;
    }

    // 把onMessage函数上报的Buffer数据，转成string类型的数据返回
    std::string retrieveAllAsString()
    {
        return retrieveAsString(readableBytes()); // 应用可读数据的长度
    }

    std::string retrieveAsString(size_t len)
    {
        std::string result(peek(),len);
        retrieve(len); // 上面一句把缓冲区数据中可读的数据，已经读取出来，这里肯定要对缓冲区进行复位操作
        return result;
    }

    // buffer_.size() - writerIndex_   len
    void ensurewritableBytes(size_t len)
    {
        if(writableBytes() < len)
        {
            makeSpace(len); // 扩容
        }
    }

    // 把[data,data+len]内存上的数据，添加到writeable缓冲区
    void append(const char* data,size_t len)
    {
        ensurewritableBytes(len);
        std::copy(data,data+len,beginWrite());
        writerIndex_ += len;
    }

    char* beginWrite()
    {
        return begin() + writerIndex_;
    }

    const char* beginWrite() const
    {
        return begin() + writerIndex_;
    }

    // 从fd里面读取数据
    size_t readFd(int fd,int* saveErrno);
    // 通过fd发送数据
    size_t writeFd(int fd,int* saveErrno);
private:
    char* begin()
    {
        // *buffer_.begin() => it.operator*()
        return &*buffer_.begin(); // vector底层数组首元素的地址，也就是数组的起始地址
    }

    const char* begin() const
    {
        // *buffer_.begin() => it.operator*()
        return &*buffer_.begin(); // vector底层数组首元素的地址，也就是数组的起始地址
    }

    void makeSpace(size_t len)
    {
        if(writableBytes() + prependableBytes() < len + kCheapPrepend)
        {
            buffer_.resize(writerIndex_ + len);
        }
        else
        {
            size_t readable = readableBytes();
            std::copy(begin() + readerIndex_,
                    begin() + writerIndex_,
                    begin() + kCheapPrepend);// 中间这一段的数据拷贝到缓冲区起始位置
            readerIndex_ = kCheapPrepend;
            writerIndex_ = readerIndex_ + readable;
        }
    }
    std::vector<char> buffer_; // 析构的时候vertor底层自动释放
    size_t readerIndex_;
    size_t writerIndex_;
};